﻿/**
 * Licensed under the MIT License
 *
 * Copyright (c) 2010 Laurent Berthelot
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */
package marcel.display.draw
{
	import flash.display.BitmapData;
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.display.Graphics;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.geom.ColorTransform;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import marcel.debug.*;
	import marcel.display.draw.props.CornerProps;
	import marcel.display.draw.props.EllipseProps;
	import marcel.display.draw.props.FillProps;
	import marcel.display.draw.props.LineProps;
	import marcel.display.draw.props.PolygonProps;
	import marcel.display.draw.shapes.EllipseShape;
	import marcel.display.draw.shapes.PolygonShape;
	import marcel.display.draw.shapes.RectangleShape;
	import marcel.display.draw.shapes.StarShape;
	import marcel.utils.ArrayUtils;
	import marcel.utils.ColorUtils;
	import marcel.utils.Delegate;
	
	
	/**
	 * DrawManager class contains a set of static methods that you can used to draw vectors shapes.
	* @author	Laurent BERTHELOT
	*/
	public class DrawManager extends Object {
		
		//--------------------------------------------------------------------------
		//
		//  Constructor
		//
		//--------------------------------------------------------------------------
		/**
		 * Non-instanciable class, only statics methods in DrawManager class.
		 */
		public function DrawManager(o:ConstructorAccess) {}
		
		//--------------------------------------------------------------------------
		//
		//  Public static methods
		//
		//--------------------------------------------------------------------------
		/**
		 * Draws a rectangle.
		 * @param	target	DisplayObject to draw on.
		 * @param	rec		Rectangle size.
		 * @param	fp		Fill properties.
		 * @param	lp		Line style properties.
		 * @param	cp		Corner properties.
		 * @return	The DisplayObject instance that you pass in the target parameter.
		 */
		public static function drawRect(target:DisplayObject, rec:Rectangle, fp:FillProps = null, lp:LineProps = null, cp:CornerProps = null):DisplayObject {
			var _target:DisplayObject = target ? __getTarget(target) : new Shape();
			RectangleShape.drawShape(__getGraphics(_target), rec, lp, fp, cp);
			return _target;
		}
		
		/**
		 * Draws an ellipse.
		 * @param	target	DisplayObject to draw on.
		 * @param	ep		Ellipse properties.
		 * @param	fp		Fill properties.
		 * @param	lp		Line style properties.
		 * @return	The DisplayObject instance that you pass in the target parameter.
		 */
		public static function drawEllipse(target:DisplayObject, ep:EllipseProps = null, fp:FillProps = null, lp:LineProps = null):DisplayObject {
			var _target:DisplayObject = target ? __getTarget(target) : new Shape();
			EllipseShape.drawShape(__getGraphics(_target), ep, fp, lp);
			return _target
		}
		
		/**
		 * Draws a polygon.
		 * @param	target	DisplayObject to draw on.
		 * @param	pp		Polygon properties.
		 * @param	close	Specify if the shape is closed (true) or not (false).
		 * @param	fp		Fill properties.
		 * @param	lp		Line style properties.
		 * @return	The DisplayObject instance that you pass in the target parameter.
		 */
		public static function drawPolygon(target:DisplayObject, pp:PolygonProps = null, close:Boolean = true, fp:FillProps = null, lp:LineProps = null):DisplayObject {
			var _target:DisplayObject = target ? __getTarget(target) : new Shape();
			PolygonShape.drawShape(__getGraphics(_target), pp, close, fp, lp);
			return _target;
		}
		
		/**
		 * Draws a star.
		 * @param	target		DisplayObject to draw on.
		 * @param	arms		Number of arm.
		 * @param	radius		Radius of the star.
		 * @param	radiusInner	Inner radius of the star.
		 * @param	fp			Fill properties.
		 * @param	lp			Line style properties.
		 * @return	The DisplayObject instance that you pass in the target parameter.
		 */
		public static function drawStar(target:DisplayObject, arms:Number = 3, radius:Number = 0, radiusInner:Number = 0, fp:FillProps = null, lp:LineProps = null):DisplayObject {
			var _target:DisplayObject = target ? __getTarget(target) : new Shape();
			StarShape.drawShape(__getGraphics(_target), arms, radius, radiusInner, fp, lp);
			return _target;
		}
		
		/**
		 * Draws a pixel asset.
		 * @param	pattern	Pattern used as pixel ( BitmapUtils.getPixel() ).
		 * @param	map		Binary string representing pixel to draw.
		 * @param	dim		Dimension used to split the map.
		 * @return	The fill BitmapData.
		 */
		public static function drawPixelAsset(pattern:BitmapData, map:Array, size:Point):BitmapData {
			var _bmp:BitmapData = new BitmapData(size.x * pattern.width, size.y * pattern.height, true, 0);
			map.map(Delegate.create(__applyPatternOnMap, size, pattern, _bmp));
			return _bmp;
		}
		
		/**
		 * Draws a pixel asset.
		 * @param	pattern	Pattern used as pixel.
		 * @param	colors	Colors to use.
		 * @param	map		Binary string representing pixel to draw.
		 * @param	dim		Dimension used to split the map.
		 * @return	The fill BitmapData.
		 */
		public static function drawColoredPixelAsset(pattern:BitmapData, colors:Array, map:Array, size:Point):BitmapData {
			var _bmp:BitmapData = new BitmapData(size.x * pattern.width, size.y * pattern.height, true, 0);
			map.map(Delegate.create(__applyColoredPatternOnMap, size, pattern, _bmp, colors));
			return _bmp;
		}
		
		/**
		 * Draws a trame into new instance of Shape
		 * @param	pattern	Pattern used.
		 * @param	size	Dimension of the trame to draw.
		 * @param	matrix	A matrix object (of the flash.geom.Matrix class), which you can use to define transformations on the pattern.
		 * @param	smooth	Use smoothing to draw the trame (true) or not (false).
		 * @param	repeat 	Repeat the pattern (true) or adjust it dimension (false).
		 * @return	A new instance of Shape with the trame.
		 */
		public static function getTrame(pattern:BitmapData, size:Rectangle, matrix:Matrix = null, smooth:Boolean = false, repeat:Boolean = true):Shape {
			var _s:Shape = new Shape();
			_s.graphics.beginBitmapFill(pattern, matrix? matrix : new Matrix(), repeat, smooth);
			_s.graphics.drawRect(size.x, size.y, size.width, size.height);
			_s.graphics.endFill();
			return _s;
		}
		
		//--------------------------------------------------------------------------
		//
		//  Private static methods
		//
		//--------------------------------------------------------------------------
		/**
		 * @param	target
		 * @return
		 */
		private static function __getGraphics(target:DisplayObject):Graphics {
			return (target && target.hasOwnProperty("graphics"))? Object(target).graphics : new Graphics();
		}
		
		/**
		 *
		 * @param	target
		 * @return
		 */
		private static function __getTarget(target:DisplayObject):DisplayObject {
			if (target is Shape || target is Sprite) return target;
			if (target is DisplayObjectContainer) return (target as DisplayObjectContainer).addChild(new Shape);
			return new Shape();
		}
			
		/**
		 *
		 * @param	element
		 * @param	index
		 * @param	array
		 * @param	dim
		 * @param	pattern
		 * @param	bmp
		 */
		private static function __applyPatternOnMap(element:int, index:int, array:Array, size:Point, pattern:BitmapData, bmp:BitmapData):void {
			if (element === 0) return;
			var _p:Point = ArrayUtils.getShift(index, size);
			bmp.copyPixels(pattern, pattern.rect, new Point(_p.x * pattern.width, _p.y * pattern.height));
		}
		
		/**
		 *
		 * @param	element
		 * @param	index
		 * @param	array
		 * @param	dim
		 * @param	pattern
		 * @param	bmp
		 * @param	colors
		 */
		private static function __applyColoredPatternOnMap(element:int, index:int, array:Array, size:Point, pattern:BitmapData, bmp:BitmapData, colors:Array):void {
			if (element === 0) return;
			var _p:Point = ArrayUtils.getShift(index, size);
			var _coloredBitmap:BitmapData = pattern.clone();
			var _cu:ColorUtils = ColorUtils.hexToARGB(colors[parseInt("0x" + element) - 1]);
			_coloredBitmap.colorTransform(pattern.rect, new ColorTransform(0, 0, 0, 0, _cu.r, _cu.g, _cu.b, _cu.a));
			bmp.copyPixels(_coloredBitmap, pattern.rect, new Point(_p.x * pattern.width, _p.y * pattern.height));
		}
		
	}
}
internal class ConstructorAccess {}